package com.hyb.algorithm.data.struct.list;

/**
 * @Author: huyanbing
 * @Date: 2021/9/5 5:20 下午
 * <p>
 * https://labuladong.gitee.io/algo/2/18/18/
 * <p>
 * <p>
 * 25. K 个一组翻转链表
 * https://leetcode-cn.com/problems/reverse-nodes-in-k-group/
 */
public class ReverseK {

    /**
     * 反转以 a 为头结点的链表  反转整个连表
     */
    public ListNode reverse(ListNode a) {

        ListNode cur = a;
        ListNode pre = null;
        ListNode nxt = a;

        while (cur != null) {
            //临时存放下一个结点
            nxt = cur.next;

            //反转 指针 1->2   反转为 2->1
            cur.next = pre;

            // 临时记录前一个节点
            pre = cur;

            // 向后移动
            cur = nxt;
        }

        // 返回反转后的头结点
        return pre;
    }


    /**
     * 反转区间 [a, b) 的元素，注意是左闭右开
     */
    public ListNode reverseBetween(ListNode a, ListNode b) {

        ListNode cur = a;
        ListNode pre = null;
        ListNode nxt = a;
        // while 终止的条件改一下就行了
        while (cur != b) {
            //临时存放下一个结点
            nxt = cur.next;

            //反转 指针 1->2   反转为 2->1
            cur.next = pre;

            // 临时记录前一个节点
            pre = cur;

            // 向后移动
            cur = nxt;
        }

        // 返回反转后的头结点
        return pre;
    }


    /**
     * 反转区间 [a, a+k)
     *
     * @return
     */
    public ListNode reverseKGroup(ListNode head, int k) {

        if (head == null) {
            return null;
        }

        // 区间 [a, b) 包含 k 个待反转元素
        ListNode b = head, a = head;
        for (int i = 0; i < k; i++) {
            // 不足 k 个，不需要反转，base case
            if (b == null) {
                return head;
            }
            b = b.next;
        }

        // 反转前 k 个元素
        ListNode newHead = reverseBetween(a, b);
        // 递归反转后续链表并连接起来
        a.next = reverseKGroup(b, k);
        return newHead;
    }
}
